#include "Client.h"
#include "Server.h"
#include "GMRequestID.h"
#include "GMRequestTime.h"
#include "GMClientServerPing.h"
#include "GMClientRequestPlayer.h"
#include "Timer.h"

Client::Client() :
m_networkTimeOutCounter(0),
m_initialConnection(0),
m_connected(false),
m_id(-1),
m_time(0),
m_pingCounter(0),
m_delay(0),
m_pingStore(0),
m_numPingSent(0),
m_timerCounter(0)
{}
void Client::SendToServer(GameMessage& gm )
{
	gm.SetTimeStamp(m_time);
	if(!SendGM(gm, &m_sock))
		m_sock.Close();
}
bool Client::ConnectToServer( const std::string& IP, int port )
{
    ShutDown();
	if(!m_connected)
	{
		SDLNet_Init();
		GameMessage::StaticPrepareFactory();

		bool ret = m_sock.OpenClient(IP, port);
		if(ret && m_sock.IsOpen())
			RequestIDFromServer();
		else
			ret = false;

		if(ret && m_sock.IsOpen())
			RequestTimeUpdate();
		else
			ret = false;

		m_connected = ret;
		return ret;
	}
	return true;
}
void Client::ShutDown()
{
	if(m_connected)
		m_sock.Close();
    m_connected = false;
    m_initialConnection = 0;
}
bool Client::Listen()
{
    Networking::SockMsg msg;

    if(!m_sock.Receive(&msg))
        return true;		//on purpose. Nothing is wrong, just no data

    if(RecvGM(msg))
    {
        OUT_STRING("processed a message..");
    }
	else
		return false;

    return true;
}
void Client::RequestIDFromServer()
{
    GMRequestID id;
    SendToServer(id);
}
void Client::Update()
{
	if(m_connected)
		if(!Listen())
			m_sock.Close();

    TheTimer::Instance()->Update();
    if(m_connected && !m_sock.IsOpen())
    {
        m_connected = false;
    }
    m_time += TheTimer::Instance()->GetDtMilliSeconds();
	if(m_connected)
	{
		m_timerCounter += TheTimer::Instance()->GetDtMilliSeconds();
		if( m_timerCounter > 500)//0.5 sec
		{
			PingServer();
		}
		if( m_timerCounter > 1000)//1 sec
		{
			m_timerCounter = 0;
			RequestTimeUpdate();
		}
	}
    if(m_pingCounter > 0)
    {
        m_pingStore += TheTimer::Instance()->GetDtMilliSeconds();
		if(m_pingStore > 1000)
		{
			AcceptPing(0);
		}
    }
}
void Client::PingServer()
{
    if(m_id < 0 || m_pingCounter == 1)
    {
        return;
    }
    m_pingCounter++;        //
    m_numPingSent++;        //The overall count
    GMClientServerPing gm;
    gm.SetID(m_id);
    SendToServer(gm);
}
void Client::AcceptPing(int ts)
{
	if(ts == 0)
	{
		// pluss framerate seconds..
		m_networkTimeOutCounter++;
		//wait 3 seconds
		if(m_networkTimeOutCounter > 6 && m_connected)
		{
			m_networkTimeOutCounter = 0;
			m_sock.Invalidate();
		}
	}
	else
		m_networkTimeOutCounter = 0;
    m_pingCounter--;
    if(m_pingCounter < 0)
    {
        OUT_STRING("PANIC");
		m_pingCounter = 0;
    }
    OUT_STRING("Current Latency: " << m_delay << " New Latency: " << m_pingStore);
    OUT_STRING("Current Timestamp: " << m_time << " ServerClientPing Timestamp: " << ts );
    int diff = m_time - ts;
    OUT_STRING("Time Difference: " << diff);
	//that was there and back
    m_delay = m_pingStore / 2;
    m_pingStore = 0;
}
void Client::RequestTimeUpdate()
{
    GMRequestTime timeReq;
    SendToServer(timeReq);
}
void Client::SetID( int id )
{
    m_id = id;
    if(IsInitialConnection())
    {
        GMClientRequestPlayer gcp;
        gcp.SetID(m_id);
        SendToServer(gcp);
		PingServer();
    }
}

